package com.tintintech.sendmail.util;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.Map;

import com.sleepycat.je.Cursor;
import com.sleepycat.je.Database;
import com.sleepycat.je.DatabaseConfig;
import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.LockMode;
import com.sleepycat.je.OperationStatus;
import com.tintintech.sendmail.Config;
import com.tintintech.sendmail.helper.DataHelper;

/**
 * @author frk
 */
public class MailStore {

    public Environment env = null;
    public Database db = null;
    public Cursor cursor = null;
    
    public static String DB_NAME = "MAIL_STORE";
    public static String FAILED_NAME = "FAILED_STORE";
    public static String LOG_NAME = "MAIL_LOG_STORE";
    
    public MailStore(String path, long cacheSize) {
        this.initEnv(path, cacheSize);
    }

    public EnvironmentConfig envConfig;
    public void initEnv(String path, long cacheSize) {
        envConfig = new EnvironmentConfig();
        envConfig.setAllowCreate(true);
        envConfig.setCacheSize(cacheSize);
        envConfig.setTransactional(false);
        envConfig.setSharedCache(true);
        try {
            env = new Environment(new File(path), envConfig);
        } catch (DatabaseException e) {
            e.printStackTrace();
        }
    }
    
    public DatabaseConfig dbConfig;
    public void open(String dbName) {

        dbConfig = new DatabaseConfig();
        dbConfig.setAllowCreate(true);
        try {
            db = env.openDatabase(null, dbName, dbConfig);
        } catch (DatabaseException e) {
            e.printStackTrace();
        }
    }
    
    public void dbClose()
    {
        this.cursorClose();
        if (db != null)
        {
            db.close();
            db = null;
        }
    }
    
    public void envClose()
    {
        if (env != null)
        {
        	env.sync();
        	env.cleanLog();
            env.close();
        }
    }
    
    public void sync()
    {
        env.sync();
    }
    
    public void close() {
        try {
            this.cursorClose();
            this.dbClose();
            this.envClose();
        } catch (Throwable e) {
            
        }
    }
    
    public String get(String key) {
        DatabaseEntry queryKey = new DatabaseEntry();
        DatabaseEntry value = new DatabaseEntry();
        try {
            queryKey.setData(key.getBytes("UTF-8"));
        } catch (UnsupportedEncodingException e){}
        
        OperationStatus status = db.get(null, queryKey, value,
        LockMode.DEFAULT);
        if (status == OperationStatus.SUCCESS) {
            return new String(value.getData());
        }
        return null;
    }
    
    public void load()
    {
    	this.open(DB_NAME);
    	saveFailedMailbox();
    	MailStat.BDB_STORE_NUM.set(new Long(this.count()).intValue());
    	this.openCursor();
    	DatabaseEntry foundkey = new DatabaseEntry();
    	DatabaseEntry foundValue = new DatabaseEntry();
    	String key = null;
    	String data = null;
    	int point = new Integer(Config.GLOBALS.get("queueSize")).intValue();
    	int i = point, xiaofei_queue_size = DataHelper.MAIL_QUEUE.size();
    	while (cursor.getNext(foundkey, foundValue, LockMode.DEFAULT) == OperationStatus.SUCCESS)
    	{
    		System.out.println(".cursor.");
    		MailStat.DB_GET_NUM.incrementAndGet();
    		try {
    			key = new String(foundkey.getData(), "UTF-8");
    			data = new String(foundValue.getData(), "UTF-8");
    			if (key != null && data != null)
    			{
    				final Map<String, String> mailBox = DataHelper.JSON.decodeForMap(data);
    				final String status = mailBox.get("status");
    				if (status == null)
    				{//第一次发送
    					mailBox.put("status", "#1");
    					DataHelper.MAILMAP_QUEUE.put(mailBox);
    				}
    				else if ("#1".equals(status))
    				{//第二次发送
//    					System.out.println("##########");
    					mailBox.put("status", "#2");
    					DataHelper.MAILMAP_QUEUE.put(mailBox);
    				}
    				else 
    				{//发送两次以上的直接删掉
//    					System.out.println("3-" + status);
    				}
    				MailStat.BDB_STORE_NUM.decrementAndGet();
    				this.delete(key);
    			}
    			xiaofei_queue_size++;
    			if (i == xiaofei_queue_size)
    			{
    				System.out.println("===");
    				break;
    			}
    		}
    		catch (UnsupportedEncodingException uee) {
    			uee.printStackTrace();
    		}
    		catch (InterruptedException inpe) {
    			System.out.println("loadData Wait 中断");
    			inpe.printStackTrace();
    		}
    		catch (Exception e) {
    			System.out.println("loadData debug");
    			e.printStackTrace();
    		}
    		
    	}
    	env.sync();
    	this.dbClose();
    	System.out.println("load-end-sync");
    	return;
    }
    
    public void saveFailedMailbox()
    {
    	String value = null;
    	for (String key : DataHelper.SEND_FAILED_MAP.keySet())
    	{
    		if (key != null)
    		{
    			value = DataHelper.SEND_FAILED_MAP.get(key);
    			if (key.endsWith("#1") && value != null)
    			{//失败两次了就直接删除了。
    				this.put(key, value);
    				MailStat.BDB_STORE_NUM.incrementAndGet();
    			}
    		}
    	}
    	DataHelper.SEND_FAILED_MAP.clear();
    }
    
    public void loadData()
    {
    	MailStat.MAILBOX_LOAD_DATA.set(true);
        this.open(DB_NAME);
        MailStat.BDB_STORE_NUM.set(new Long(this.count()).intValue());
        saveFailedMailbox();        
    	this.openCursor();
    	DatabaseEntry foundkey = new DatabaseEntry();
    	DatabaseEntry foundValue = new DatabaseEntry();
    	String key = null;
    	String data = null;
    	int point = new Integer(Config.GLOBALS.get("queueSize")).intValue();
    	
    	int i = point, xiaofei_queue_size = DataHelper.MAIL_QUEUE.size();
    	while (cursor.getNext(foundkey, foundValue, LockMode.DEFAULT) == OperationStatus.SUCCESS)
    	{
    		System.out.println(".cursor.");
    		try {
    			key = new String(foundkey.getData(), "UTF-8");
    			data = new String(foundValue.getData(), "UTF-8");
    			if (key != null && data != null)
    			{
    				DataHelper.MAIL_QUEUE.put(key);
    				DataHelper.MAILBOX_MAP.put(key, data);
    				MailStat.BDB_STORE_NUM.decrementAndGet();
    				this.delete(key);
    			}
    			xiaofei_queue_size++;
    			if (i == xiaofei_queue_size)
    			{
    				System.out.println("===");
    				break;
    			}
    		}
    		catch (UnsupportedEncodingException uee) {
    			uee.printStackTrace();
    		}
    		catch (InterruptedException inpe) {
    			System.out.println("loadData Wait 中断");
    			inpe.printStackTrace();
    		}
    		catch (Exception e) {
    			System.out.println("loadData debug");
    		}
    		
    	}
    
    	env.sync();
    	this.dbClose();
    	MailStat.MAILBOX_LOAD_DATA.set(false);
    	System.out.println("load-end");
    	return;
    }
    
    public void cursorClose()
    {
        if (cursor != null)
        {
            cursor.close();
            cursor = null;
        }
    }
    
    public long getCountByCursor()
    {
    	this.openCursor();
    	return cursor.count();
    }
    
    public void openCursor()
    {
        if (cursor == null)
        {
            cursor = db.openCursor(null, null);
        }
    }
    
    public boolean put(String key, String value) {
        try {
            byte[] theKey = key.getBytes("UTF-8");
            byte[] theValue = value.getBytes("UTF-8");
            if (db.put(null, new DatabaseEntry(theKey), new DatabaseEntry(theValue)) == OperationStatus.SUCCESS) {
                MailStat.DB_PUT_NUM.incrementAndGet();
            	return true;
            }
        } catch (UnsupportedEncodingException e) {
            
        }

        return false;
    }

    public boolean delete(String key)
    {
        try {
            DatabaseEntry k = new DatabaseEntry(key.getBytes("UTF-8"));
            if (db.delete(null, k) == OperationStatus.SUCCESS) {
            	MailStat.DB_DElETE_NUM.incrementAndGet();
                return true;
            }            
        }
        catch (UnsupportedEncodingException uee) {}
        catch (Throwable e) {
        	System.out.println("bdb-delete-err");
        	e.printStackTrace();
        }
        
        return false;
    }
    
    public void dropDatabase(String db)
    {
    	env.removeDatabase(null, db);
        env.sync();
    }
    
    public long truncateDatabase(String db)
    {
        return env.truncateDatabase(null, db, true);
    }
    
    public String getCurrentDatabase()
    {
        return db.getDatabaseName();
    }
    
    public void deleteDatabaseFiles(String uri)
    {
    	File dir = new File(uri);
    	if (dir.exists() && dir.isDirectory())
    	{
    		for (File f : dir.listFiles())
    		{
    			f.delete();
    		}
    	}
    }
    
    public long count()
    {
        return db.count();
    }
}
